package ferp.core.player;

import ferp.core.game.Bid;
import ferp.core.game.Game;
import ferp.core.game.Input;
import ferp.core.game.Settings;
import ferp.core.state.State;

/**
 * User: olegs
 * Date: 19/05/11 15:12
 */
public class Human extends Player
{
  public Human(Game g, int id, String name) {super(id, name);}

  public final void reset(Game g) {super.reset(g, true);}

  @Override
  public int setBiddingInputOptions(Game g, Input.Options io) {return State.Result.SHOW_OPTIONS;}

  @Override
  public int setDroppingInputOptions(Game g, Settings settings, Input input, Input.Options io)
  {
    io.set(Input.Options.DROP);

    if (canWithout3(g, settings))
      io.set(Input.Options.WITHOUT3);

    io.hand = g.getHand(id()).current;

    return State.Result.SHOW_OPTIONS;
  }

  @Override
  public int setContractingInputOptions(Game g, Input.Options io) {return State.Result.SHOW_OPTIONS;}

  @Override
  public int setContractingInputOptionsCheck10(Input.Options io)
  {
    io.set(Input.Options.TRICKING_10_CONFIRM);

    return State.Result.SHOW_OPTIONS;
  }

  @Override
  public int setStandInputOptions(Input.Options io)
  {
    io.set(Input.Options.STAND);

    return State.Result.SHOW_OPTIONS;
  }

  @Override
  public void setPassingInputOptions(Game.Listener listener, Game g) throws Game.Error
  {
    super.setPassingInputOptions(listener, g);

    setMovingInputOptions(g);

    listener.onBestScoreRequested(g);

    if (ferp.core.ai.tree2.Score.isComplete(g.options.score))
    {
      g.options.set(Input.Options.NO_MORE_TRICKS);
      g.options.set(Input.Options.REST_TRICKS_ARE_MINE);
    }
  }

  @Override
  public void setMisereInputOptions(Game.Listener listener, Game g) throws Game.Error
  {
    super.setMisereInputOptions(listener, g);

    setMovingInputOptions(g);

    listener.onBestScoreRequested(g);

    if (ferp.core.ai.tree2.Score.isComplete(g.options.score))
    {
      // show "no more tricks" only for declarer
      if (g.declarer() == this)
        g.options.set(Input.Options.NO_MORE_TRICKS);

      g.options.set(Input.Options.REST_TRICKS_ARE_MINE);
    }
  }

  @Override
  public void setTrickingInputOptions(Game.Listener listener, Game g) throws Game.Error
  {
    super.setTrickingInputOptions(listener, g);

    setMovingInputOptions(g);

    int contract = g.contract();
    // total opponents tricks - don't use g.getOpponentTricks() and g.getPasserTricks() as this method might be called for 'Tricking10' mode,
    //                          where opponent and passer might not exist when playing in 'Checking 10' mode
    int ot = g.getTricks(Game.next(g.player.declarer)) + g.getTricks(Game.previous(g.player.declarer));

    listener.onBestScoreRequested(g);

    if (ferp.core.ai.tree2.Score.isComplete(g.options.score))
    {
      if (g.isOpen())
      {
        // actual declarer's trick
        int adt = g.getTricks(g.player.declarer);
        // potential declarer's tricks
        int pdt = Game.MAXIMUM_TRICKS - ot;

        if (ot <= Game.MAXIMUM_TRICKS - contract)
        {
          // "plus" offers
          setOffers(g, adt, pdt, contract + 1, contract + 3, Input.Options.TRICKS_BY_CONTRACT_PLUS_1);
          // "by contract" offer
          setOffers(g, adt, pdt, contract, contract, Input.Options.TRICKS_BY_CONTRACT);
        }
        else
          if (g.declarer() == this)
          {
            g.options.set(Input.Options.NO_MORE_TRICKS);
            g.options.set(Input.Options.REST_TRICKS_ARE_MINE);
          }

        // "minus" offers
        setOffers(g, adt, pdt, contract - 3, contract - 1, Input.Options.TRICKS_BY_CONTRACT_MINUS_3);
      }
/*
      // for now we do not show any option for standing type games
      else
      {
        // only for declarer
        if (g.declarer() == this)
        {
          g.options.set(Input.Options.NO_MORE_TRICKS);
          g.options.set(Input.Options.REST_TRICKS_ARE_MINE);
        }
      }
*/
    }
  }

  @Override
  public void bid(Game.Listener listener, Game g, Settings settings, Input input)
  {
    // assign human bid
    g.setCurrentBid(id(), new Bid(input.bid));

    // signal if first human bid
    if (++g.getBid(id()).count == 1)
      listener.onFirstHumanBid(g, this);

    Game.log(g, ("human bid, input=" + input.bid));
  }

  @Override
  public void contract(Game g, Settings settings, Input input)
  {
    Bid bid = g.options.isSet(Input.Options.TRICKING_10_CONFIRM) ? Bid.pass() : new Bid(input.bid);

    g.setBid(id(), bid, bid);

    Game.log(g, ("human contract, input=" + input.bid));
  }

  @Override
  public void drop(Game g, Input input)
  {
    // copy player input to the drop
    for (int i = 0; i < Game.TALON_SIZE; ++i)
      g.setDrop(i, input.drop[i]);
  }

  @Override
  public void setGameType(Game g, Input input)
  {
    g.type = input.stand ? Game.Type.STANDING : Game.Type.OPEN;
  }

  @Override
  public void setCheck10(Game g, Input input)
  {
    g.check10 = input.check10;
  }

  private void setMovingInputOptions(Game g)
  {
    g.options.hand = Hand.getMoveCandidates(g, g.getCurrentPlayerHand().current);
  }

  private void setOffers(Game g, int adt, int pdt, int min, int max, int option)
  {
    for (int contract = min; contract <= max; ++contract)
    {
      if (adt <= contract && contract <= pdt)
        g.options.set(option);

      option <<= 1;
    }
  }
}
